#include "EventLoop.h"

void EventLoop::addSocket() const
{
    epoll_event evt{};
    evt.data.fd = _acc.fd();
    evt.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, _acc.fd(), &evt);
    ERR_CHECK(ret, -1, "addSocket");
}

bool EventLoop::isClosed(int cltFd) const
{
    char buf[10];
    int ret = ::recv(cltFd, buf, sizeof(buf), MSG_PEEK);
    return (ret == 0);
}

EventLoop::EventLoop(Acceptor &acc)
    : _epfd{epoll_create(1)}, _isLooping{false}, _acc(acc), _evts(1024)
{
    ERR_CHECK(_epfd, -1, "EventLoop");
    addSocket();
}

void EventLoop::loop()
{
    _isLooping = true;
    while (_isLooping)
    {
        epollWait();
    }
}

void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::epollWait()
{
    int nready = epoll_wait(_epfd, &*_evts.begin(), _evts.size(), 5000);
    if (-1 == nready)
    {
        perror("epollWait");
        exit(-1);
    }
    else if (0 == nready)
    {
        cout << ">> epoll_wait timeout ..." << endl;
    }
    else
    {

        if (nready == _evts.size())
        {
            _evts.resize(_evts.size() * 2);
        }

        for (size_t idx{}; idx < nready; idx++)
        {
            // 如果是新的连接
            if (_evts[idx].data.fd == _acc.fd() && _evts[idx].events & EPOLLIN)
            {
                int cltFd = _acc.accept();
                addEventCtl(cltFd);
                addTcp(cltFd);
            }
            else
            {
                handleMessage(_evts[idx].data.fd);
            }
        }
    }
}

void EventLoop::addEventCtl(int cltFd) const
{
    epoll_event evt{};
    evt.data.fd = cltFd;
    evt.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, cltFd, &evt);
    ERR_CHECK(ret, -1, "addEventCtl");
}

void EventLoop::addTcp(int cltFd)
{
    auto iter = _tcps.find(cltFd);
    if (iter == _tcps.end())
    {
        TcpConnectPtr ptr = make_shared<TcpConnect>(cltFd);

        ptr->setConnectCallback(_connectCallback);
        ptr->setHandleMessageCallback(_handleMessageCallback);
        ptr->setCloseCallback(_closeCallback);

        _tcps.insert(iter, make_pair(cltFd, ptr));

        ptr->handleConnect();
    }
}

void EventLoop::delEventClt(int cltFd)
{
    epoll_event evt{};
    evt.data.fd = cltFd;
    evt.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_DEL, cltFd, &evt);
    ERR_CHECK(ret, -1, "delEventClt");
}

void EventLoop::delTcp(const map<int, TcpConnectPtr>::iterator &iter)
{
    _tcps.erase(iter);
}

void EventLoop::handleMessage(int cltFd)
{
    auto iter = _tcps.find(cltFd);
    // 如果当前是客户端断开连接事件
    if (isClosed(cltFd))
    {
        delEventClt(cltFd);
        iter->second->handleClose();
        delTcp(iter);
    }
    else
    {
        // 正常的读事件处理
        iter->second->handleMessage();
    }
}

void EventLoop::setConnectCallback(Callback &&cb)
{
    _connectCallback = std::move(cb);
}

void EventLoop::setHandleMessage(Callback &&cb)
{
    _handleMessageCallback = std::move(cb);
}

void EventLoop::setCloseCallback(Callback &&cb)
{
    _closeCallback = std::move(cb);
}